#!/usr/bin/env python3

import glob
import os
import tempfile
import subprocess
import sys


def uncpio(srcrpm, dest):
    os.makedirs(dest)
    print('extracting ', srcrpm)
    p1 = subprocess.Popen(['rpm2cpio', srcrpm], stdout=subprocess.PIPE)
    subprocess.check_call(['cpio', '--extract', '--make-directories'],
        stdin=p1.stdout, cwd=dest)
    err = p1.wait()
    if err != 0:
        raise RuntimeError('rpm2cpio %s returned %d' % (srcrpm, err))


def find_spec(thedir):
    def doit():
        for dirpath, dirnames, filenames in os.walk(thedir):
            for name in filenames:
                if name.endswith('.spec'):
                    yield os.path.join(dirpath, name)
    specs = list(doit())
    count = len(specs)
    if count == 0:
        raise RuntimeError(f'Could not find any specs in "{thedir}"')
    elif count > 1:
        raise RuntimeError(f'{count} specs have been found in "{thedir}"')
    else:
        return specs[0]


def rpmbuild_bp(spec, name, tmpd):
    builddir = os.path.join(tmpd, 'build')
    srcdir = os.path.join(tmpd, name)

    cmd = [
        'rpmbuild',
        '--define', f'_builddir {builddir}',
        '--define', f'_sourcedir {srcdir}',
        '--nodeps',
        '-bp',
        spec,
    ]
    os.makedirs(builddir)
    subprocess.check_call(cmd) 


def find_source(tmpd):
    def doit():
        with os.scandir(os.path.join(tmpd, 'build')) as it:
            for entry in it:
                if entry.is_dir() and not entry.name.startswith('.'):
                    yield entry

    subdirs = list(doit())
    count = len(subdirs)
    if count == 0:
        raise RuntimeError('No sources could be found in %s' % tmpd)
    elif count > 1:
        raise RuntimeError('Multiple subdirs available in %s' % tmpd)
    else:
        return subdirs[0]


def name_from_spec(spec):
    cmd = ['rpmspec', '-q', '--qf', '%{name}\n', spec]
    out = subprocess.check_output(cmd, stdin=subprocess.DEVNULL,
        encoding='utf-8')
    subpackages = out.strip().split('\n')
    if len(subpackages) == 0:
        raise RuntimeError('name_from_spec: no packages found in %s' % spec)
    name = subpackages[0].strip()
    print('spec ', spec, ', name: ', name)
    return name


def extract_patched_sources(srcrpm):
    name = srcrpm.removesuffix('.src.rpm')
    with tempfile.TemporaryDirectory(prefix=name) as tmpdirname:
        d1 = os.path.join(tmpdirname, name)
        uncpio(srcrpm, d1)
        spec = find_spec(d1)
        pkgname = name_from_spec(spec)
        rpmbuild_bp(spec, name, tmpdirname)
        srcdir_with_version = find_source(tmpdirname)
        srcdir = os.path.join(tmpdirname, pkgname)
        os.rename(srcdir_with_version, srcdir)
        subprocess.check_call(['cp', '-a', '--target-directory=.', srcdir])


if __name__ == '__main__':
    if len(sys.argv) > 1:
        for srcrpm in sys.argv[1:]:
            extract_patched_sources(srcrpm)
